home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / io / BufferedInputStream.java next >
Encoding:
Java Source  |  1999-05-28  |  13.7 KB  |  411 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)BufferedInputStream.java    1.36 98/08/18
  3.  *
  4.  * Copyright 1994-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. /**
  18.  * A <code>BufferedInputStream</code> adds
  19.  * functionality to another input stream-namely,
  20.  * the ability to buffer the input and to
  21.  * support the <code>mark</code> and <code>reset</code>
  22.  * methods. When  the <code>BufferedInputStream</code>
  23.  * is created, an internal buffer array is
  24.  * created. As bytes  from the stream are read
  25.  * or skipped, the internal buffer is refilled
  26.  * as necessary  from the contained input stream,
  27.  * many bytes at a time. The <code>mark</code>
  28.  * operation  remembers a point in the input
  29.  * stream and the <code>reset</code> operation
  30.  * causes all the  bytes read since the most
  31.  * recent <code>mark</code> operation to be
  32.  * reread before new bytes are  taken from
  33.  * the contained input stream.
  34.  *
  35.  * @author  Arthur van Hoff
  36.  * @version 1.36, 08/18/98
  37.  * @since   JDK1.0
  38.  */
  39. public
  40. class BufferedInputStream extends FilterInputStream {
  41.  
  42.     private static int defaultBufferSize = 2048;
  43.  
  44.     /**
  45.      * The internal buffer array where the data is stored. When necessary,
  46.      * it may be replaced by another array of
  47.      * a different size.
  48.      */
  49.     protected byte buf[];
  50.  
  51.     /**
  52.      * The index one greater than the index of the last valid byte in 
  53.      * the buffer. 
  54.      * This value is always
  55.      * in the range <code>0</code> through <code>buf.length</code>;
  56.      * elements <code>buf[0]</code>  through <code>buf[count-1]
  57.      * </code>contain buffered input data obtained
  58.      * from the underlying  input stream.
  59.      */
  60.     protected int count;
  61.  
  62.     /**
  63.      * The current position in the buffer. This is the index of the next 
  64.      * character to be read from the <code>buf</code> array. 
  65.      * <p>
  66.      * This value is always in the range <code>0</code>
  67.      * through <code>count</code>. If it is less
  68.      * than <code>count</code>, then  <code>buf[pos]</code>
  69.      * is the next byte to be supplied as input;
  70.      * if it is equal to <code>count</code>, then
  71.      * the  next <code>read</code> or <code>skip</code>
  72.      * operation will require more bytes to be
  73.      * read from the contained  input stream.
  74.      *
  75.      * @see     java.io.BufferedInputStream#buf
  76.      */
  77.     protected int pos;
  78.     
  79.     /**
  80.      * The value of the <code>pos</code> field at the time the last 
  81.      * <code>mark</code> method was called.
  82.      * <p>
  83.      * This value is always
  84.      * in the range <code>-1</code> through <code>pos</code>.
  85.      * If there is no marked position in  the input
  86.      * stream, this field is <code>-1</code>. If
  87.      * there is a marked position in the input
  88.      * stream,  then <code>buf[markpos]</code>
  89.      * is the first byte to be supplied as input
  90.      * after a <code>reset</code> operation. If
  91.      * <code>markpos</code> is not <code>-1</code>,
  92.      * then all bytes from positions <code>buf[markpos]</code>
  93.      * through  <code>buf[pos-1]</code> must remain
  94.      * in the buffer array (though they may be
  95.      * moved to  another place in the buffer array,
  96.      * with suitable adjustments to the values
  97.      * of <code>count</code>,  <code>pos</code>,
  98.      * and <code>markpos</code>); they may not
  99.      * be discarded unless and until the difference
  100.      * between <code>pos</code> and <code>markpos</code>
  101.      * exceeds <code>marklimit</code>.
  102.      *
  103.      * @see     java.io.BufferedInputStream#mark(int)
  104.      * @see     java.io.BufferedInputStream#pos
  105.      */
  106.     protected int markpos = -1;
  107.  
  108.     /**
  109.      * The maximum read ahead allowed after a call to the 
  110.      * <code>mark</code> method before subsequent calls to the 
  111.      * <code>reset</code> method fail. 
  112.      * Whenever the difference between <code>pos</code>
  113.      * and <code>markpos</code> exceeds <code>marklimit</code>,
  114.      * then the  mark may be dropped by setting
  115.      * <code>markpos</code> to <code>-1</code>.
  116.      *
  117.      * @see     java.io.BufferedInputStream#mark(int)
  118.      * @see     java.io.BufferedInputStream#reset()
  119.      */
  120.     protected int marklimit;
  121.  
  122.     /**
  123.      * Check to make sure that this stream has not been closed
  124.      */
  125.     private void ensureOpen() throws IOException {
  126.     if (in == null)
  127.         throw new IOException("Stream closed");
  128.     }
  129.  
  130.     /**
  131.      * Creates a <code>BufferedInputStream</code>
  132.      * and saves its  argument, the input stream
  133.      * <code>in</code>, for later use. An internal
  134.      * buffer array is created and  stored in <code>buf</code>.
  135.      *
  136.      * @param   in   the underlying input stream.
  137.      */
  138.     public BufferedInputStream(InputStream in) {
  139.     this(in, defaultBufferSize);
  140.     }
  141.  
  142.     /**
  143.      * Creates a <code>BufferedInputStream</code>
  144.      * with the specified buffer size,
  145.      * and saves its  argument, the input stream
  146.      * <code>in</code>, for later use.  An internal
  147.      * buffer array of length  <code>size</code>
  148.      * is created and stored in <code>buf</code>.
  149.      *
  150.      * @param   in     the underlying input stream.
  151.      * @param   size   the buffer size.
  152.      * @exception IllegalArgumentException if size <= 0.
  153.      */
  154.     public BufferedInputStream(InputStream in, int size) {
  155.     super(in);
  156.         if (size <= 0) {
  157.             throw new IllegalArgumentException("Buffer size <= 0");
  158.         }
  159.     buf = new byte[size];
  160.     }
  161.  
  162.     /**
  163.      * Fills the buffer with more data, taking into account
  164.      * shuffling and other tricks for dealing with marks.
  165.      * Assumes that it is being called by a synchronized method.
  166.      * This method also assumes that all data has already been read in,
  167.      * hence pos > count.
  168.      */
  169.     private void fill() throws IOException {
  170.     if (markpos < 0)
  171.         pos = 0;        /* no mark: throw away the buffer */
  172.     else if (pos >= buf.length)    /* no room left in buffer */
  173.         if (markpos > 0) {    /* can throw away early part of the buffer */
  174.         int sz = pos - markpos;
  175.         System.arraycopy(buf, markpos, buf, 0, sz);
  176.         pos = sz;
  177.         markpos = 0;
  178.         } else if (buf.length >= marklimit) {
  179.         markpos = -1;    /* buffer got too big, invalidate mark */
  180.         pos = 0;    /* drop buffer contents */
  181.         } else {        /* grow buffer */
  182.         int nsz = pos * 2;
  183.         if (nsz > marklimit)
  184.             nsz = marklimit;
  185.         byte nbuf[] = new byte[nsz];
  186.         System.arraycopy(buf, 0, nbuf, 0, pos);
  187.         buf = nbuf;
  188.         }
  189.         count = pos;
  190.     int n = in.read(buf, pos, buf.length - pos);
  191.         if (n > 0)
  192.             count = n + pos;
  193.     }
  194.  
  195.     /**
  196.      * See
  197.      * the general contract of the <code>read</code>
  198.      * method of <code>InputStream</code>.
  199.      *
  200.      * @return     the next byte of data, or <code>-1</code> if the end of the
  201.      *             stream is reached.
  202.      * @exception  IOException  if an I/O error occurs.
  203.      * @see        java.io.FilterInputStream#in
  204.      */
  205.     public synchronized int read() throws IOException {
  206.         ensureOpen();
  207.     if (pos >= count) {
  208.         fill();
  209.         if (pos >= count)
  210.         return -1;
  211.     }
  212.     return buf[pos++] & 0xff;
  213.     }
  214.  
  215.     /**
  216.      * Read characters into a portion of an array, reading from the underlying
  217.      * stream at most once if necessary.
  218.      */
  219.     private int read1(byte[] b, int off, int len) throws IOException {
  220.     int avail = count - pos;
  221.     if (avail <= 0) {
  222.         /* If the requested length is at least as large as the buffer, and
  223.            if there is no mark/reset activity, do not bother to copy the
  224.            bytes into the local buffer.  In this way buffered streams will
  225.            cascade harmlessly. */
  226.         if (len >= buf.length && markpos < 0) {
  227.         return in.read(b, off, len);
  228.         }
  229.         fill();
  230.         avail = count - pos;
  231.         if (avail <= 0) return -1;
  232.     }
  233.     int cnt = (avail < len) ? avail : len;
  234.     System.arraycopy(buf, pos, b, off, cnt);
  235.     pos += cnt;
  236.     return cnt;
  237.     }
  238.  
  239.     /**
  240.      * Reads bytes from this byte-input stream into the specified byte array,
  241.      * starting at the given offset.
  242.      *
  243.      * <p> This method implements the general contract of the corresponding
  244.      * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
  245.      * the <code>{@link InputStream}</code> class.  As an additional
  246.      * convenience, it attempts to read as many bytes as possible by repeatedly
  247.      * invoking the <code>read</code> method of the underlying stream.  This
  248.      * iterated <code>read</code> continues until one of the following
  249.      * conditions becomes true: <ul>
  250.      *
  251.      *   <li> The specified number of bytes have been read,
  252.      *
  253.      *   <li> The <code>read</code> method of the underlying stream returns
  254.      *   <code>-1</code>, indicating end-of-file, or
  255.      *
  256.      *   <li> The <code>available</code> method of the underlying stream
  257.      *   returns zero, indicating that further input requests would block.
  258.      *
  259.      * </ul> If the first <code>read</code> on the underlying stream returns
  260.      * <code>-1</code> to indicate end-of-file then this method returns
  261.      * <code>-1</code>.  Otherwise this method returns the number of bytes
  262.      * actually read.
  263.      *
  264.      * <p> Subclasses of this class are encouraged, but not required, to
  265.      * attempt to read as many bytes as possible in the same fashion.
  266.      *
  267.      * @param      b     destination buffer.
  268.      * @param      off   offset at which to start storing bytes.
  269.      * @param      len   maximum number of bytes to read.
  270.      * @return     the number of bytes read, or <code>-1</code> if the end of
  271.      *             the stream has been reached.
  272.      * @exception  IOException  if an I/O error occurs.
  273.      */
  274.     public synchronized int read(byte b[], int off, int len)
  275.     throws IOException
  276.     {
  277.         ensureOpen();
  278.     if ((off < 0) || (off > b.length) || (len < 0) ||
  279.             ((off + len) > b.length) || ((off + len) < 0)) {
  280.         throw new IndexOutOfBoundsException();
  281.     } else if (len == 0) {
  282.         return 0;
  283.     }
  284.  
  285.     int n = read1(b, off, len);
  286.     if (n <= 0) return n;
  287.     while ((n < len) && (in.available() > 0)) {
  288.         int n1 = read1(b, off + n, len - n);
  289.         if (n1 <= 0) break;
  290.         n += n1;
  291.     }
  292.     return n;
  293.     }
  294.  
  295.     /**
  296.      * See the general contract of the <code>skip</code>
  297.      * method of <code>InputStream</code>.
  298.      *
  299.      * @param      n   the number of bytes to be skipped.
  300.      * @return     the actual number of bytes skipped.
  301.      * @exception  IOException  if an I/O error occurs.
  302.      */
  303.     public synchronized long skip(long n) throws IOException {
  304.         ensureOpen();
  305.     if (n <= 0) {
  306.         return 0;
  307.     }
  308.     long avail = count - pos;
  309.      
  310.         if (avail <= 0) {
  311.             // If no mark position set then don't keep in buffer
  312.             if (markpos <0) 
  313.                 return in.skip(n);
  314.             
  315.             // Fill in buffer to save bytes for reset
  316.             fill();
  317.             avail = count - pos;
  318.             if (avail <= 0)
  319.                 return 0;
  320.         }
  321.         
  322.         long skipped = (avail < n) ? avail : n;
  323.         pos += skipped;
  324.         return skipped;
  325.     }
  326.  
  327.     /**
  328.      * Returns the number of bytes that can be read from this input 
  329.      * stream without blocking. 
  330.      * <p>
  331.      * The <code>available</code> method of 
  332.      * <code>BufferedInputStream</code> returns the sum of the the number 
  333.      * of bytes remaining to be read in the buffer 
  334.      * (<code>count - pos</code>) 
  335.      * and the result of calling the <code>available</code> method of the 
  336.      * underlying input stream. 
  337.      *
  338.      * @return     the number of bytes that can be read from this input
  339.      *             stream without blocking.
  340.      * @exception  IOException  if an I/O error occurs.
  341.      * @see        java.io.FilterInputStream#in
  342.      */
  343.     public synchronized int available() throws IOException {
  344.         ensureOpen();
  345.     return (count - pos) + in.available();
  346.     }
  347.  
  348.     /** 
  349.      * See the general contract of the <code>mark</code>
  350.      * method of <code>InputStream</code>.
  351.      *
  352.      * @param   readlimit   the maximum limit of bytes that can be read before
  353.      *                      the mark position becomes invalid.
  354.      * @see     java.io.BufferedInputStream#reset()
  355.      */
  356.     public synchronized void mark(int readlimit) {
  357.     marklimit = readlimit;
  358.     markpos = pos;
  359.     }
  360.  
  361.     /**
  362.      * See the general contract of the <code>reset</code>
  363.      * method of <code>InputStream</code>.
  364.      * <p>
  365.      * If <code>markpos</code> is <code>-1</code>
  366.      * (no mark has been set or the mark has been
  367.      * invalidated), an <code>IOException</code>
  368.      * is thrown. Otherwise, <code>pos</code> is
  369.      * set equal to <code>markpos</code>.
  370.      *
  371.      * @exception  IOException  if this stream has not been marked or
  372.      *               if the mark has been invalidated.
  373.      * @see        java.io.BufferedInputStream#mark(int)
  374.      */
  375.     public synchronized void reset() throws IOException {
  376.         ensureOpen();
  377.     if (markpos < 0)
  378.         throw new IOException("Resetting to invalid mark");
  379.     pos = markpos;
  380.     }
  381.  
  382.     /**
  383.      * Tests if this input stream supports the <code>mark</code> 
  384.      * and <code>reset</code> methods. The <code>markSupported</code> 
  385.      * method of <code>BufferedInputStream</code> returns 
  386.      * <code>true</code>. 
  387.      *
  388.      * @return  a <code>boolean</code> indicating if this stream type supports
  389.      *          the <code>mark</code> and <code>reset</code> methods.
  390.      * @see     java.io.InputStream#mark(int)
  391.      * @see     java.io.InputStream#reset()
  392.      */
  393.     public boolean markSupported() {
  394.     return true;
  395.     }
  396.  
  397.     /**
  398.      * Closes this input stream and releases any system resources 
  399.      * associated with the stream. 
  400.      *
  401.      * @exception  IOException  if an I/O error occurs.
  402.      */
  403.     public synchronized void close() throws IOException {
  404.         if (in == null)
  405.             return;
  406.         in.close();
  407.         in = null;
  408.         buf = null;
  409.     }
  410. }
  411.